package com.azunitech.apm.bundles.admin;

import java.util.Dictionary;
import java.util.Hashtable;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.felix.http.api.ExtHttpService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;
import org.osgi.service.log.LogListener;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Monitors the HttpService status and registers content availability as either the 
 * HttpService or this bundle stops and starts.
 */
public class Activator implements BundleActivator, ServiceTrackerCustomizer<HttpService, HttpService> {

	private static final Logger log = LoggerFactory.getLogger(Activator.class);
	
	private BundleContext bundleContext;
	private ServiceTracker<HttpService, HttpService> tracker;
	
	//Make thread can access this varible
	private LogServiceListener m_LogListener;
	
	
	/**
	 * Start tracking the HttpService when this bundle starts.
	 */
	public void start(BundleContext context) throws Exception {
		log.debug("admin-servlet bundle is starting");
		bundleContext = context;

		m_LogListener = new LogServiceListener();
		synchronized( m_LogListener){
			String logServiceFilter = "(" + Constants.OBJECTCLASS + "=" + LogService.class.getName() + ")";
			bundleContext.addServiceListener(m_LogListener, logServiceFilter);
			ServiceReference[] refs = bundleContext.getAllServiceReferences(null, logServiceFilter); 
			if ( refs != null ){
				for( ServiceReference r : refs){
					m_LogListener.serviceChanged( new ServiceEvent( ServiceEvent.REGISTERED, r));
				}
			}
		}
		
		LogService logService = m_LogListener.getLogService();
		//Using it
		
		
		tracker = new ServiceTracker<HttpService,HttpService>(context, HttpService.class.getName(), this);
		tracker.open();

		 ServiceReference sRef = context.getServiceReference(ExtHttpService.class.getName());  
		  
		  if (sRef != null) {  
		   Dictionary properties = new Hashtable();  
		   properties.put("service.pid", CharacterEncodingFilter.class.getName());  
		   properties.put("init.charencoding.filter.encoding", "UTF-8");  
		   properties.put("init.charencoding.filter.forceencoding", "true");  
		   ExtHttpService service = (ExtHttpService) context.getService(sRef);  
		   service.registerFilter(new CharacterEncodingFilter(), "/.*", properties, 0, null);  
		  }  		
	}

	/**
	 * Cancel HttpService tracking when the bundle is stopped.
	 */
	public void stop(BundleContext context) throws Exception {
		log.debug("admin-servlet bundle is stopping");
	    tracker.close();
	}

	
	/**
	 * Process ServiceTracker callbacks to register this module's servlets 
	 * with each HttpService that comes available.
	 */
	public HttpService addingService(ServiceReference<HttpService> reference) {
		HttpService httpService = bundleContext.getService(reference);
		mountContent(httpService);
		return httpService;
	}

	/**
	 * No action is required when the HttpService is modified.
	 */
	public void modifiedService(ServiceReference<HttpService> reference, HttpService service) {
	}

	/**
	 * Process ServiceTracker callbacks to unregister this module's servlets
	 * from HttpServices that are going away.
	 */
	public void removedService(ServiceReference<HttpService> reference, HttpService service) {
		HttpService httpService = bundleContext.getService(reference);
		dismountContent(httpService);
	}

	/**
	 * Register all servlets provided by this bundle for access
	 * via a HttpService.
	 * 
	 * @TODO For a production system it is important to handle
	 *       NamespaceExceptions otherwise we will silently
	 *       trash another bundle's registrations when we
	 *       unregister.
	 *        
	 * @param httpService Non-null HttpService to register with.
	 */
	private void mountContent(HttpService httpService) {
		try {
			log.debug("Registering /admin servlet with service " + httpService);
			httpService.registerServlet("/admin", new AdminServlet(), null, null);
			httpService.registerResources("/admin/assets", "/assets", null);
			httpService.registerResources("/web/demos","/demos",null);
			
		}
		catch (Exception ex) {
			log.warn("Could not register servlets", ex);
		}
	}

	/**
	 * Remove servlet registrations from the stated HttpService.
	 * 
	 * @TODO For a production system, don't unregister an alias unless
	 *       we know it was registered by this bundle previously.
	 *       
	 * @param httpService HttpService to unregister. Must not be null.
	 */
	private void dismountContent(HttpService httpService) {
		log.debug("Unregistering /admin servlet");
		httpService.unregister("/admin");
		httpService.unregister("/admin/assets");
	}
	
	class LogServiceListener implements ServiceListener{
		SortedSet<ServiceReference<?>> m_LogServiceReferenceList = new TreeSet<ServiceReference<?>>();
		public synchronized void serviceChanged(ServiceEvent event) {
			switch(event.getType()){
				case ServiceEvent.REGISTERED:{
					m_LogServiceReferenceList.add(event.getServiceReference());
					break;
				}
				case ServiceEvent.MODIFIED:{
					break;
				}
				case ServiceEvent.UNREGISTERING:{
					m_LogServiceReferenceList.remove(event.getServiceReference());
				}
				default: break;
			}
		}
		
		public synchronized LogService getLogService(){
			if ( this.m_LogServiceReferenceList.size() > 0 ){
				return (LogService) bundleContext.getService(m_LogServiceReferenceList.last());
			}
			return null;
		}
	}
}
